home *** CD-ROM | disk | FTP | other *** search
- /* Routines for dealing with segmented figures */
-
- /* Original implementation written by Bernie Roehl, March 1992 */
-
- /* Major paradigm shift to current form: Dave Stampe, Aug. '92 */
-
- // The theoretical basis for segments is that of
- // cascading transformation to implement jointed
- // objects. The new paradigm goes even further,
- // using segments for moving body parts, lights, viewpoints
- // and so on. New methods for efficient updating were
- // added, and the ability to use matrices to control motion added
-
- // Changes, Jan. '93 by Dave Stampe for Release 5:
- // added joint angle caching, fixed up the attach/detach
- // so they work properly. Worked out fast automatic updates:
- // see statmach.c
-
- // MASSIVE changes for VR-386, including POSE, and multiple
- // lists, composite objects... just about everything
- // VR-386 changes by Dave Stampe, last as of 9/1/94
-
- /*
- This code is part of the VR-386 project, created by Dave Stampe.
- VR-386 is a desendent of REND386, created by Dave Stampe and
- Bernie Roehl. Almost all the code has been rewritten by Dave
- Stampre for VR-386.
-
- Copyright (c) 1994 by Dave Stampe:
- May be freely used to write software for release into the public domain
- or for educational use; all commercial endeavours MUST contact Dave Stampe
- (dstampe@psych.toronto.edu) for permission to incorporate any part of
- this software or source code into their products! Usually there is no
- charge for under 50-100 items for low-cost or shareware products, and terms
- are reasonable. Any royalties are used for development, so equipment is
- often acceptable payment.
-
- ATTRIBUTION: If you use any part of this source code or the libraries
- in your projects, you must give attribution to VR-386 and Dave Stampe,
- and any other authors in your documentation, source code, and at startup
- of your program. Let's keep the freeware ball rolling!
-
- DEVELOPMENT: VR-386 is a effort to develop the process started by
- REND386, improving programmer access by rewriting the code and supplying
- a standard API. If you write improvements, add new functions rather
- than rewriting current functions. This will make it possible to
- include you improved code in the next API release. YOU can help advance
- VR-386. Comments on the API are welcome.
-
- CONTACT: dstampe@psych.toronto.edu
- */
-
-
-
- #include <stdio.h>
- #include <alloc.h>
- #include <string.h>
-
- #define SEGDEF 1
-
- typedef struct _segment SEGMENT;
-
- #include "3dstruct.h"
- #include "vr_api.h"
- #include "intmath.h"
- #include "segment.h"
-
-
- struct _segment {
- unsigned flags; /* if bit 0 set, segment has been modified */
- SEGMENT *parent, *child, *sibling;
- MATRIX jmatrix; /* joint relationship */
- MATRIX pmatrix; /* world position */
- OBJECT *object;
- long rx, ry, rz; /* added for animation control */
- SEGMENT *root;
- SEGMENT *update_next; // used for updating automatically
- SEGMENT *update_prev;
- char *name;
- unsigned fix_count; /* used to fix scale after rel_rotate */
- };
-
- //other uses of flags: for segments and object:
-
- #define IS_OBJECT 0x8000 // VROBJECT specifiers
- #define IS_SEGMENT 0x0080
- #define SYSTEM_OWNED 0x0040 // owned by light, camera, or body
- #define HAS_OBJECT 0x0020 // has a visible OBJECT attached
- #define IS_MOVEABLE 0x0010 // segment or attached object
-
- #define SEG_MODIFIED 1 // modified position
- #define OBJ_MODIFIED 2 // representation only changed
-
- #define ON_UPDATE_LIST 0x0008 // update list status
- #define NOT_ON_UPDATE_LIST 0xFFF7
-
- #define UPDATED_MASK 0xFFF0 // used to reset when processed
- #define SEG_EXTERNAL_FLAGS_MASK 0xFFFF // what externals can see
-
- static int fix_init = 100;
-
-
- SEGMENT *new_seg(SEGMENT *parent)
- {
- SEGMENT *s;
-
- if ((s = malloc(sizeof(SEGMENT))) == NULL) return NULL;
- s->parent = parent;
- s->child = NULL;
- if (parent)
- {
- s->sibling = parent->child;
- parent->child = s;
- }
- else s->sibling = NULL;
-
- identity_matrix(s->jmatrix);
- if (parent) memcpy(&(s->pmatrix), &(parent->pmatrix), sizeof(MATRIX));
- else identity_matrix(s->pmatrix);
-
- s->object = NULL;
- s->flags = IS_SEGMENT | SEG_MODIFIED | IS_MOVEABLE;
- s->name = NULL;
- s->root = (parent) ? parent->root : s; // update root
- s->rx = s->ry = s->rz = 0;
- s->fix_count = fix_init;
- s->update_next = NULL;
- s->update_prev = NULL;
- fix_init = (fix_init+7) & 0x7F; /* pseudorandom to prevent clumping */
-
- return s;
- }
-
-
- /////// SEGMENT SUPPORT
-
- void seg_set_object(SEGMENT *s, VISOBJ *obj)
- {
- s->object = obj;
- obj->owner = s;
- obj->oflags |= IS_MOVEABLE;
- s->flags |= OBJ_MODIFIED | HAS_OBJECT;
- update_segment(s); // so object is current
- }
-
-
- void seg_reset_object(SEGMENT *s, VISOBJ *obj)
- {
- s->object = NULL;
- obj->owner = NULL;
- obj->oflags &= (~IS_MOVEABLE);
- s->flags &= (~HAS_OBJECT);
- }
-
-
- void *seg_get_object(SEGMENT *s)
- {
- return s->object;
- }
-
- char *seg_getname(SEGMENT *s)
- {
- return s->name;
- }
-
- void seg_setname(SEGMENT *s, char *name)
- {
- s->name = strdup(name);
- }
-
- void seg_getpose(SEGMENT *s, POSE *p)
- {
- p->x = s->jmatrix[3][0];
- p->y = s->jmatrix[3][1];
- p->z = s->jmatrix[3][2];
- p->rx = s->rx;
- p->ry = s->ry;
- p->rz = s->rz;
- }
-
- void seg_getmatpose(SEGMENT *s, POSE *p)
- {
- p->x = s->jmatrix[3][0];
- p->y = s->jmatrix[3][1];
- p->z = s->jmatrix[3][2];
- matrix_to_angle(s->jmatrix, &p->rx, &p->ry, &p->rz);
- s->rx = p->rx;
- s->ry = p->ry;
- s->rz = p->rz;
- }
-
-
- void seg_getworldpose(SEGMENT *s, POSE *p)
- {
- p->x = s->pmatrix[3][0];
- p->y = s->pmatrix[3][1];
- p->z = s->pmatrix[3][2];
- matrix_to_angle(s->pmatrix, &p->rx, &p->ry, &p->rz);
- }
-
-
- void seg_setpose(SEGMENT *s, POSE *p)
- {
- if(p->x!=DONTCARE) s->jmatrix[3][0] = p->x;
- if(p->y!=DONTCARE) s->jmatrix[3][1] = p->y;
- if(p->z!=DONTCARE) s->jmatrix[3][2] = p->z;
- if(p->rx!=DONTCARE) s->rx = p->rx;
- if(p->ry!=DONTCARE) s->ry = p->ry;
- if(p->rz!=DONTCARE) s->rz = p->rz;
- multi_matrix(s->jmatrix, s->rx, s->ry, s->rz,
- s->jmatrix[3][0], s->jmatrix[3][1], s->jmatrix[3][2], RYXZ);
- s->flags |= SEG_MODIFIED;
- }
-
- void seg_getposang(SEGMENT *s, long *rx, long *ry, long *rz)
- {
- matrix_to_angle(s->pmatrix, rx, ry, rz);
- }
-
- void seg_getjointang(SEGMENT *s, long *rx, long *ry, long *rz)
- {
- matrix_to_angle(s->jmatrix, rx, ry, rz);
- s->rx = *rx;
- s->ry = *ry; /* ADDED FOR ANIMATION */
- s->rz = *rz;
- }
-
- void seg_getrxyz(SEGMENT *s, long *rx, long *ry, long *rz)
- {
- *rx = s->rx; /* ADDED FOR ANIMATION */
- *ry = s->ry;
- *rz = s->rz;
- }
-
- void seg_getposxyz(SEGMENT *s, long *x, long *y, long *z)
- {
- if(x) *x = s->pmatrix[3][0];
- if(y) *y = s->pmatrix[3][1];
- if(z) *z = s->pmatrix[3][2];
- }
-
- void seg_getjointxyz(SEGMENT *s, long *x, long *y, long *z)
- {
- *x = s->jmatrix[3][0];
- *y = s->jmatrix[3][1];
- *z = s->jmatrix[3][2];
- }
-
-
- void abs_move_segment(SEGMENT *s, long tx, long ty, long tz)
- {
- s->jmatrix[3][0] = tx;
- s->jmatrix[3][1] = ty;
- s->jmatrix[3][2] = tz;
- s->flags |= SEG_MODIFIED;
- }
-
- void rel_move_segment(SEGMENT *s, long tx, long ty, long tz)
- {
- s->jmatrix[3][0] += tx;
- s->jmatrix[3][1] += ty;
- s->jmatrix[3][2] += tz;
- s->flags |= SEG_MODIFIED;
- }
-
-
- void abs_mat_segment(SEGMENT *s, MATRIX m)
- {
- memcpy(s->jmatrix, m, sizeof(MATRIX));
- s-> flags |= SEG_MODIFIED;
- }
-
-
- void rel_mat_segment(SEGMENT *s, MATRIX m)
- {
- matrix_product(s->jmatrix, m, s->jmatrix);
- s-> flags |= SEG_MODIFIED;
- s->fix_count--;
- if (s->fix_count == 0)
- {
- s->fix_count = fix_init;
- fix_init = (fix_init+7) & 0x7F; /* pseudorandom to prevent clumping */
- renormalize_matrix(s->jmatrix);
- }
- }
-
-
- void abs_rotmat_segment(SEGMENT *s, MATRIX m)
- {
- s->jmatrix[0][0] = m[0][0];
- s->jmatrix[0][1] = m[0][1];
- s->jmatrix[0][2] = m[0][2];
- s->jmatrix[1][0] = m[1][0];
- s->jmatrix[1][1] = m[1][1];
- s->jmatrix[1][2] = m[1][2];
- s->jmatrix[2][0] = m[2][0];
- s->jmatrix[2][1] = m[2][1];
- s->jmatrix[2][2] = m[2][2];
- s->flags |= SEG_MODIFIED;
- }
-
-
- void rel_rotmat_segment(SEGMENT *s, MATRIX m)
- {
- matrix_mult(s->jmatrix, m, s->jmatrix);
- s-> flags |= SEG_MODIFIED;
- s->fix_count--;
- if (s->fix_count == 0)
- {
- s->fix_count = fix_init;
- fix_init = (fix_init+7) & 0x7F; /* pseudorandom to prevent clumping */
- renormalize_matrix(s->jmatrix);
- }
- }
-
- #define RXYZ 1 /* matrix rotation orders */
- #define RYXZ 0 /* ONLY RYXZ guaranteed to be tested */
- #define RXZY 2
- #define RZYX 5
- #define RZXY 4
- #define RYZX 6
-
- void abs_rot_segment(SEGMENT *s, long rx, long ry, long rz, int order)
- {
- MATRIX m;
- multi_matrix(m, rx, ry, rz, 0, 0, 0, order);
- s->rx = rx;
- s->ry = ry; /* ADDED FOR ANIMATION */
- s->rz = rz;
- abs_rotmat_segment(s, m);
- }
-
- void rel_rot_segment(SEGMENT *s, long rx, long ry, long rz, int order)
- {
- MATRIX m;
- multi_matrix(m, rx, ry, rz, 0, 0, 0, order);
- rel_rotmat_segment(s, m);
- }
-
-
- extern void split_move_handler(OBJECT *obj); // the default
-
- static void (*move_handler)(OBJECT *) = split_move_handler; /* called when object moved */
-
- void set_move_handler(void (*move_handler_ptr)(OBJECT *))
- {
- move_handler = move_handler_ptr;
- }
-
-
- void full_update_segment(SEGMENT *seg)
- {
- SEGMENT *s;
- OBJECT *obj;
-
- if(!seg) return;
- remove_from_segment_update_list(seg);
- seg->flags &= UPDATED_MASK;
- if (seg->parent)
- matrix_product(seg->parent->pmatrix, seg->jmatrix, seg->pmatrix);
- else
- memcpy(&(seg->pmatrix), &(seg->jmatrix), sizeof(MATRIX));
-
- if ((obj = seg->object)!=NULL && (seg->flags&HAS_OBJECT))
- {
- matmove_osphere(obj, seg->pmatrix);
- obj->owner = seg; /* just to be safe... */
- if (move_handler) move_handler(obj); /* this moves in split tree */
- }
-
- for (s = seg->child; s; s = s->sibling)
- {
- s->root = seg; // keep root current!
- full_update_segment(s);
- }
- }
-
-
-
- void update_segment(SEGMENT *seg) /* scan till update needed */
- {
- SEGMENT *s;
- OBJECT *obj;
-
- if(!seg) return;
- remove_from_segment_update_list(seg);
- if (seg->flags & SEG_MODIFIED)
- full_update_segment(seg);
- else if (seg->flags&OBJ_MODIFIED)
- {
- if ((obj = seg->object)!=NULL && (seg->flags&HAS_OBJECT))
- {
- matmove_osphere(obj, seg->pmatrix);
- obj->owner = seg; /* just to be safe... */
- if (move_handler) move_handler(obj); /* this moves in split tree */
- }
- }
- else
- for (s = seg->child; s; s = s->sibling)
- {
- s->root = seg;
- update_segment(s);
- }
- }
-
- // update object in world only
- void update_object(OBJECT *obj)
- {
- SEGMENT *s = object2segment(obj);
- if(!s) return;
- s->flags |= OBJ_MODIFIED;
- // if (move_handler) move_handler(obj); /* this moves in split tree */
- update_segment(s);
- }
-
- // moderate update
- void physical_update_object(OBJECT *obj)
- {
- SEGMENT *s = object2segment(obj);
- compute_object(obj);
- if(!s) return;
- s->flags |= OBJ_MODIFIED | SEG_MODIFIED;
- update_segment(s);
- }
-
- // truly massive update
- void global_update_object(OBJECT *obj)
- {
- SEGMENT *s = object2segment(obj);
- compute_all_object(obj);
- if(!s) return;
- s->flags |= OBJ_MODIFIED | SEG_MODIFIED;
- s = find_root_segment(s);
- full_update_segment(s);
- }
-
-
-
- int seg_get_flags(SEGMENT *s)
- {
- return s->flags & SEG_EXTERNAL_FLAGS_MASK;
- }
-
-
- void seg_set_flags(SEGMENT *s, int f)
- {
- s->flags = (s->flags&(~SEG_EXTERNAL_FLAGS_MASK))|(f&SEG_EXTERNAL_FLAGS_MASK);
- }
-
-
- SEGMENT *parent_segment(SEGMENT *s)
- {
- return s->parent;
- }
-
-
- SEGMENT *child_segment(SEGMENT *s)
- {
- return s->child;
- }
-
-
- SEGMENT *sibling_segment(SEGMENT *s)
- {
- return s->sibling;
- }
-
-
- MATRIX *get_seg_jmatrix(SEGMENT *s)
- {
- return &s->jmatrix;
- }
-
-
- MATRIX *get_seg_pmatrix(SEGMENT *s)
- {
- return &s->pmatrix;
- }
-
-
- void detach_segment(SEGMENT *s, BOOL preserve) /* assumes segment is updated! */
- {
- SEGMENT *p;
- MATRIX n;
-
- if ((p = s->parent) == NULL) return;
- s->parent = NULL;
- if (preserve)
- memcpy(&(s->jmatrix), &(s->pmatrix), sizeof(MATRIX));
- s->flags |= SEG_MODIFIED;
-
- if (p->child == s)
- {
- p->child = s->sibling;
- s->sibling = NULL;
- s->root = s;
- update_segment(s);
- return;
- }
- for (p = p->child; p->sibling; p = p->sibling)
- if (p->sibling == s)
- {
- p->sibling = s->sibling;
- s->sibling = NULL;
- s->root = s;
- update_segment(s);
- return;
- }
- s->root = s;
- update_segment(s);
- }
-
-
- void detach_object(OBJECT *obj, BOOL preserve)
- {
- SEGMENT *p = object2segment(obj);
- if(!p) return;
- detach_segment(p, preserve);
- }
-
-
- /* assumes parent is updated! */
- // preserves world position if flagged
- void attach_segment(SEGMENT *s, SEGMENT *to, BOOL preserve)
- {
- MATRIX m,n;
-
- if (s->parent) detach_segment(s, preserve);
- s->parent = to;
- s->sibling = to->child;
- to->child = s;
- s->root = to->root; //find_root_segment(s);
-
- if(preserve) // preserves world position
- {
- inverse_matrix(to->pmatrix, m);
- matrix_product(m, s->pmatrix, s->jmatrix);
- }
- // to->flags |= SEG_MODIFIED;
- s->flags |= SEG_MODIFIED;
- update_segment(to); // at least changes roots
- }
-
- // used for loading objects, to ensure they don't
- // get moved in world or taken off objlist
- // be sure to update <to> later!
- void naked_attach_object(OBJECT *obj, OBJECT *to)
- {
- SEGMENT *p, *q;
- p = object2segment(obj);
- if(!p) return;
- q = object2segment(to);
- if(!q) return;
-
- p->parent = q;
- p->sibling = q->child;
- q->child = p;
- p->root = q->root; //find_root_segment(q);
-
- p->flags |= SEG_MODIFIED | OBJ_MODIFIED;
- }
-
-
- void attach_object(OBJECT *obj, OBJECT *to, BOOL preserve)
- {
- SEGMENT *p, *q;
- p = object2segment(obj);
- if(!p) return;
- q = object2segment(to);
- if(!q) return;
- attach_segment(p, q, preserve);
- }
-
-
- void destroy_segment(SEGMENT *s) // just removes segment
- {
- SEGMENT *p, *q;
-
- detach_segment(s,1); /* first detach us from our parent */
- p = s->child; /* then recursively detach all our child segments */
- while (p)
- {
- q = p->sibling;
- detach_segment(p,1);
- p = q;
- }
- remove_from_segment_update_list(s);
- free(s);
- }
-
-
- // delete segment, descendents and objects
- void delete_object_and_children(OBJECT *obj)
- {
- SEGMENT *p, *q;
- SEGMENT *s = object2segment(obj);
-
- if(!s) return;
-
- detach_segment(s,0); /* first detach us from our parent */
- p = s->child; /* then recursively delete all our child segments */
- while (p)
- {
- q = p->sibling;
- delete_object_and_children(p);
- p = q;
- }
- if (s->object && (s->flags&HAS_OBJECT) ) // object to delete?
- delete_visobj(s->object);
- remove_from_segment_update_list(s);
- if(!(s->flags&SYSTEM_OWNED)) // delete if not camera/light segment
- free(s);
- }
-
-
- // marks segment as protected from recursive deletes
- void register_system_segment(SEGMENT *s)
- {
- s->flags |= SYSTEM_OWNED;
- }
-
-
-
- /////// SEGMENT AUTO-UPDATE
-
-
- static SEGMENT *update_list_root = NULL;
-
-
- // dump entire list
- void clear_object_update_list()
- {
- SEGMENT *sn;
- SEGMENT *s = update_list_root;
- while(s)
- {
- sn = s->update_next;
- s->flags &= NOT_ON_UPDATE_LIST;
- s->update_next = NULL;
- s->update_prev = NULL;
- s = sn;
- }
- update_list_root = NULL;
- }
-
-
- void remove_from_segment_update_list(SEGMENT *seg)
- {
- if(!(seg->flags&ON_UPDATE_LIST)) return;
- if(!seg->update_prev) // first in list
- {
- update_list_root = seg->update_next;
- if(update_list_root)
- update_list_root->update_prev = NULL; // only one
- }
- else
- {
- seg->update_prev->update_next = seg->update_next;
- if(seg->update_next)
- seg->update_next->update_prev = seg->update_prev;
- }
-
- seg->flags &= NOT_ON_UPDATE_LIST;
- }
-
-
- void remove_from_object_update_list(OBJECT *obj)
- {
- SEGMENT *s = object2segment(obj);
- if(s) remove_from_segment_update_list(s);
- }
-
- // puts root on update list
- void add_to_object_update_list(OBJECT *obj)
- {
- SEGMENT *s, *seg = object2segment(obj);
- if(!seg) return;
- s = seg->root;
- if(!s) return; // hey! hey!
- if(s->flags&ON_UPDATE_LIST) return; // already on list
-
- s->update_next = update_list_root; // add to list
- if(update_list_root)
- update_list_root->update_prev = s;
- s->update_prev = NULL;
- update_list_root = s;
- s->flags |= ON_UPDATE_LIST;
- }
-
-
- BOOL process_object_update_list()
- {
- SEGMENT *sn;
- SEGMENT *s = update_list_root;
-
- if(!s) return FALSE;
-
- while(s)
- {
- sn = s->update_next;
- update_segment(s);
- s->flags &= NOT_ON_UPDATE_LIST;
- s->update_next = NULL;
- s->update_prev = NULL;
- s = sn;
- }
- update_list_root = NULL;
- return TRUE;
- }
-
-
- SEGMENT *find_root_segment(SEGMENT *s) // try to do without
- {
- SEGMENT *ss = s;
- while (s->parent) s = s->parent;
- ss->root = s; /* ADDED FOR ANIMATION */
- return s;
- }
-
-
- OBJECT *find_root_object(OBJECT *obj) // try to do without
- {
- SEGMENT *ss = object2segment(obj);
- SEGMENT *s = ss;
-
- if(!s) return NULL;
- while (s->parent) s = s->parent;
- ss->root = s;
- return s;
- }
-
-
- SEGMENT *get_root_segment(SEGMENT *s)
- {
- return s->root; /* ADDED FOR ANIMATION */
- }
-
-
-
- VISOBJ *object2visobj(OBJECT *obj)
- {
- if(!obj) return NULL;
- if(is_object_visobj(obj)) return obj;
- return ((SEGMENT *)obj)->object;
- }
-
-
-
-
- //////// RELATIONAL ITEMS
-
- BOOL is_object_child_of(OBJECT *parent, OBJECT *child)
- {
- SEGMENT *s = object2segment(parent);
- SEGMENT *g = object2segment(child);
-
- if(!s || !g) return FALSE;
- if(s==g) return TRUE;
- while(g->parent)
- {
- if(g->parent==s) return TRUE;
- g = g->parent;
- }
- return FALSE;
- }
-
-
- BOOL are_objects_related(OBJECT *o1, OBJECT *o2)
- {
- SEGMENT *p = object2segment(o1);
-
- if(!p) return FALSE;
- if(p->root) p = p->root;
-
- return is_object_child_of(p,o2);
- }
-
-
- BOOL is_object_selected(OBJECT *obj)
- {
- VISOBJ *v = object2visobj(obj);
- if(!v) return FALSE;
- return ((v->oflags&(OBJ_HIGHLIGHTED|OBJ_INVIS))==OBJ_HIGHLIGHTED);
- }
-
- BOOL is_object_visible(OBJECT *obj)
- {
- VISOBJ *v = object2visobj(obj);
- if(!v) return FALSE;
- return ((v->oflags&OBJ_INVIS)==0);
- }
-
- BOOL is_object_selectable(OBJECT *obj)
- {
- VISOBJ *v = object2visobj(obj);
- if(!v) return FALSE;
- return ((v->oflags&OBJ_NONSEL)==0);
- }
-
-
- static void do_child_recurse(SEGMENT *p, void(* fn)(OBJECT *))
- {
- fn(p);
- for (p = p->child; p; p = p->sibling) do_child_recurse(p, fn);
- }
-
- static void do_visible_child_recurse(SEGMENT *p, void(* fn)(OBJECT *))
- {
- if(is_object_visible(p)) fn(p);
- for (p = p->child; p; p = p->sibling) do_child_recurse(p, fn);
- }
-
- static void do_selected_child_recurse(SEGMENT *p, void(* fn)(OBJECT *))
- {
- if(is_object_selected(p)) fn(p);
- for (p = p->child; p; p = p->sibling) do_child_recurse(p, fn);
- }
-
-
- void do_for_all_child_objects(OBJECT *obj, void(* fn)(OBJECT *))
- {
- SEGMENT *p = object2segment(obj);
- fn(obj);
- if(!p) return;
- for (p = p->child; p; p = p->sibling)
- do_child_recurse(p, fn);
- }
-
-
- void do_for_visible_child_objects(OBJECT *obj, void(* fn)(OBJECT *))
- {
- SEGMENT *p = object2segment(obj);
- if (is_object_visible(obj)) fn(obj);
- if(!p) return;
- for (p = p->child; p; p = p->sibling)
- do_visible_child_recurse(p, fn);
- }
-
-
- void do_for_selected_child_objects(OBJECT *obj, void(* fn)(OBJECT *))
- {
- SEGMENT *p = object2segment(obj);
- if (is_object_selected(obj)) fn(obj);
- if(!p) return;
- for (p = p->child; p; p = p->sibling)
- do_selected_child_recurse(p, fn);
- }
-
-
- void do_for_all_related_objects(OBJECT *obj, void(* fn)(OBJECT *))
- {
- SEGMENT *p = object2segment(obj);
-
- if(!p) return;
- if(p->root) p = p->root;
- do_for_all_child_objects(p, fn);
- }
-
-
- void do_for_visible_related_objects(OBJECT *obj, void(* fn)(OBJECT *))
- {
- SEGMENT *p = object2segment(obj);
-
- if(!p) return;
- if(p->root) p = p->root;
- do_for_visible_child_objects(p, fn);
- }
-
-
- void do_for_selected_related_objects(OBJECT *obj, void(* fn)(OBJECT *))
- {
- SEGMENT *p = object2segment(obj);
-
- if(!p) return;
- if(p->root) p = p->root;
- do_for_selected_child_objects(p, fn);
- }
-
-
-
- ///// object pose
-
- void get_object_pose(OBJECT *obj, POSE *p)
- {
- SEGMENT *s = object2segment(obj);
-
- if(!s) return;
- p->x = s->jmatrix[3][0];
- p->y = s->jmatrix[3][1];
- p->z = s->jmatrix[3][2];
- p->rx = s->rx;
- p->ry = s->ry;
- p->rz = s->rz;
- }
-
-
- void get_object_matrix_pose(OBJECT *obj, POSE *p)
- {
- SEGMENT *s = object2segment(obj);
-
- if(!s) return;
- p->x = s->jmatrix[3][0];
- p->y = s->jmatrix[3][1];
- p->z = s->jmatrix[3][2];
- matrix_to_angle(s->jmatrix, &s->rx, &s->ry, &s->rz);
- p->rx = s->rx;
- p->ry = s->ry;
- p->rz = s->rz;
- }
-
-
- void get_object_world_pose(OBJECT *obj, POSE *p)
- {
- SEGMENT *s = object2segment(obj);
-
- if(!s) return;
- p->x = s->pmatrix[3][0];
- p->y = s->pmatrix[3][1];
- p->z = s->pmatrix[3][2];
- matrix_to_angle(s->pmatrix, &p->rx, &p->ry, &p->rz);
- }
-
- void get_object_world_position(OBJECT *obj, long *x, long *y, long *z)
- {
- SEGMENT *s = object2segment(obj);
- if(!s) return;
- if(x) *x = s->pmatrix[3][0];
- if(y) *y = s->pmatrix[3][1];
- if(z) *z = s->pmatrix[3][2];
- }
-
-
-
- void set_object_pose(OBJECT *obj, POSE *p)
- {
- SEGMENT *s = object2segment(obj);
-
- if(!s) return;
-
- if(p->x!=DONTCARE) s->jmatrix[3][0] = p->x;
- if(p->y!=DONTCARE) s->jmatrix[3][1] = p->y;
- if(p->z!=DONTCARE) s->jmatrix[3][2] = p->z;
- if(p->rx!=DONTCARE) s->rx = p->rx;
- if(p->ry!=DONTCARE) s->ry = p->ry;
- if(p->rz!=DONTCARE) s->rz = p->rz;
- multi_matrix(s->jmatrix, s->rx, s->ry, s->rz,
- s->jmatrix[3][0], s->jmatrix[3][1], s->jmatrix[3][2], RYXZ);
- s->flags |= SEG_MODIFIED;
- }
-
-
- // place object in world, even if attached!
- void set_object_world_pose(OBJECT *obj, POSE *p)
- {
- MATRIX m,n;
- POSE po;
- SEGMENT *s = object2segment(obj);
-
- if(!s) return;
- if(s->parent==NULL) // unattached: EZ
- {
- set_object_pose(obj,p);
- return;
- } // else do it the hard way
-
- if(p->rx==DONTCARE || p->ry==DONTCARE || p->rz==DONTCARE)
- {
- get_object_world_pose(obj, &po); // tough: we need world angles!
- }
- else // shortcut
- {
- po.x = s->jmatrix[3][0];
- po.y = s->jmatrix[3][1];
- po.z = s->jmatrix[3][2];
- po.rx = p->rx;
- po.ry = p->ry;
- po.rz = p->rz;
- }
- if(p->x!=DONTCARE) po.x = p->x;
- if(p->y!=DONTCARE) po.y = p->y;
- if(p->z!=DONTCARE) po.z = p->z;
- if(p->rx!=DONTCARE) po.rx = p->rx;
- if(p->ry!=DONTCARE) po.ry = p->ry;
- if(p->rz!=DONTCARE) po.rz = p->rz;
-
- multi_matrix(n, po.rx, po.ry, po.rz, po.x, po.y, po.z, RYXZ);
- inverse_matrix(s->parent->pmatrix, m); // find the required joint
- matrix_product(m, n, s->jmatrix); // matrix to meet wld pos'n
- // and cache it.
- matrix_to_angle(s->jmatrix, &s->rx, &s->ry, &s->rz);
-
- s->flags |= SEG_MODIFIED;
- }
-
-
-
- /////// misc
-
-
- OBJECT *find_segment_by_name(OBJECT *obj, char *name)
- {
- SEGMENT *p, *s = object2segment(obj);
- if(!s) return NULL;
- if (s->name) /* if this segment has a name */
- if (!stricmp(s->name, name)) /* and it matches */
- return s; /* then we've found the segment with that name */
-
- /* otherwise, recursively check all of our children and their subtrees */
- for (p = s->child; p; p = p->sibling)
- if ((s = find_segment_by_name(p, name)) != NULL) /* found it! */
- return s;
- return NULL; /* neither us nor any of our descendants has that name */
- }
-
-